package com.xuanwei.core.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.xuanwei.core.entity.bo.CouponUseBo;
import com.xuanwei.core.entity.constant.CouponConstant;
import com.xuanwei.core.entity.vo.CouponVo;
import com.xuanwei.core.enums.CouponLimitType;
import com.xuanwei.core.enums.CouponStatus;
import com.xuanwei.core.enums.CouponType;
import com.xuanwei.core.exception.XwException;
import com.xuanwei.core.service.*;
import com.xuanwei.dao.entity.*;
import com.xuanwei.dao.mapper.XwUserCouponMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author mjy
 * @since 2019-07-16
 */
@Service
@Slf4j
public class XwUserCouponServiceImpl extends ServiceImpl<XwUserCouponMapper, XwUserCoupon> implements IXwUserCouponService {

    private IXwUserCouponRecordService userCouponRecordService;

    private IXwHomepageNavigateService homepageNavigateService;

    private IXwNavigateProductService navigateProductService;


    public XwUserCouponServiceImpl(IXwUserCouponRecordService userCouponRecordService,
                                   IXwHomepageNavigateService homepageNavigateService,
                                   IXwNavigateProductService navigateProductService
    ) {
        this.userCouponRecordService = userCouponRecordService;
        this.homepageNavigateService = homepageNavigateService;
        this.navigateProductService = navigateProductService;
    }

    @Override
    public CouponUseBo isCanUse(Integer userId, Integer userCouponId, List<XwCart> carts) {
        CouponUseBo couponUseBo = new CouponUseBo();
        XwUserCoupon one = getOne(new QueryWrapper<XwUserCoupon>()
                .eq("id", userCouponId)
                .eq("user_id", userId));
        if (one == null) {
            throw new XwException("该优惠券不存在");
        }

        if (one.getStatus() == 1) {
            log.warn("该优惠券已使用");
            couponUseBo.setCanUse(false);
            couponUseBo.setReason("该优惠券已使用");
            return couponUseBo;
        }
        if (LocalDateTime.now().isAfter(one.getCouponExpireTime())) {
            couponUseBo.setCanUse(false);
            couponUseBo.setReason("该优惠券已过期");
            return couponUseBo;
        }
        //商品限制
        boolean productLimit = false;
        //金额限制
        boolean amountLimit = false;

        couponUseBo.setCanUse(false);

        if (one.getCouponType().equals(CouponType.NO_CONDITION.getCode())) {
            amountLimit = true;
        }

        if (one.getCouponType().equals(CouponType.TO_AMOUNT.getCode()) &&
                one.getCouponLimitType().equals(CouponLimitType.NO_LIMIT.getCode())) {
            BigDecimal cartTotal = getCartTotal(carts);
            if (cartTotal.compareTo(one.getCouponConditionAmount()) > -1) {
                amountLimit = true;
            }
        }

        if (one.getCouponType().equals(CouponType.TO_AMOUNT.getCode()) &&
                one.getCouponLimitType().equals(CouponLimitType.LIMIT_ACTIVITY.getCode())) {
            BigDecimal activityTotal = getActivityTotal(one.getCouponObjId(), carts);
            if (activityTotal.compareTo(one.getCouponConditionAmount()) > -1) {
                amountLimit = true;
            }
        }

        if (one.getCouponType().equals(CouponType.TO_AMOUNT.getCode()) &&
                one.getCouponLimitType().equals(CouponLimitType.LIMIT_PRODUCT.getCode())) {
            BigDecimal productTotal = getProductTotal(one.getCouponObjId(), carts);
            if (productTotal.compareTo(one.getCouponConditionAmount()) > -1) {
                amountLimit = true;
            }
        }

        if (one.getCouponLimitType().equals(CouponLimitType.NO_LIMIT.getCode())) {
            productLimit = true;
        }

        if (one.getCouponLimitType().equals(CouponLimitType.LIMIT_ACTIVITY.getCode())) {
            for (XwCart cart : carts) {
                Integer productId = cart.getProductId();
                boolean exist = homepageNavigateService.isExist(productId, one.getCouponObjId());
                if (exist) {
                    productLimit = true;
                    couponUseBo.setProductId(productId);
                    break;
                }
            }
        }

        if (one.getCouponLimitType().equals(CouponLimitType.LIMIT_PRODUCT.getCode())) {
            for (XwCart cart : carts) {
                Integer productId = cart.getProductId();
                if (one.getCouponObjId().equals(productId)) {
                    productLimit = true;
                    couponUseBo.setProductId(productId);
                    break;
                }
            }
        }

        if (productLimit && amountLimit) {
            couponUseBo.setCanUse(true);
        } else {
            if (!amountLimit) {
                couponUseBo.setReason("满" + one.getCouponConditionAmount() + "可用");
            }
            if (!productLimit) {
                couponUseBo.setReason(one.getCouponExplain());
            }
        }
        return couponUseBo;
    }

    /**
     * 获取购物车总金额
     *
     * @param carts 购物车
     * @return 总金额
     */
    private BigDecimal getCartTotal(List<XwCart> carts) {
        List<BigDecimal> collect = carts.stream().map(s ->
                s.getPrice()
                        .multiply(new BigDecimal(s.getCount())))
                .collect(Collectors.toList());
        BigDecimal sum = new BigDecimal(0);
        for (BigDecimal b : collect) {
            sum = sum.add(b);
        }
        return sum;
    }

    /**
     * 获取购物车内商品的总价格
     *
     * @param productId 商品Id
     * @param carts     购物车
     * @return 价格
     */
    private BigDecimal getProductTotal(Integer productId, List<XwCart> carts) {
        for (XwCart cart : carts) {
            if (cart.getProductId().equals(productId)) {
                return cart.getPrice().multiply(new BigDecimal(cart.getCount()));

            }
        }
        return new BigDecimal(0);
    }

    /**
     * 获取购物车内活动商品的总价格
     *
     * @param activityId 商品Id
     * @param carts      购物车
     * @return 价格
     */
    private BigDecimal getActivityTotal(Integer activityId, List<XwCart> carts) {
        BigDecimal sum = new BigDecimal(0);
        for (XwCart cart : carts) {
            XwNavigateProduct navigateProduct = navigateProductService
                    .findByNavigateIdAndProductId(activityId, cart.getProductId());

            if (navigateProduct != null) {
                sum = sum.add(cart.getPrice().multiply(new BigDecimal(cart.getCount())));
            }
        }
        return sum;
    }

    @Override
    public void consume(Integer userId, Integer userCouponId, Integer orderId) {
        //修改状态
        XwUserCoupon userCoupon = new XwUserCoupon();
        userCoupon.setId(userCouponId);
        userCoupon.setStatus(CouponStatus.USE.getCode());
        updateById(userCoupon);
        //添加记录
        XwUserCouponRecord userCouponRecord = new XwUserCouponRecord();
        userCouponRecord.setUserId(userId);
        userCouponRecord.setOrderId(orderId);
        userCouponRecord.setUserCouponId(userCouponId);
        userCouponRecord.setUseTime(LocalDateTime.now());
        userCouponRecordService.save(userCouponRecord);
    }

    @Override
    public Integer findCountByUser(Integer userId, List<XwCart> carts) {
        List<Object> objects = listObjs(new QueryWrapper<XwUserCoupon>()
                .select("id")
                .eq("user_id", userId)
                .eq("`status`", 0)
                .ge("coupon_expire_time", LocalDateTime.now()));
        int count = 0;
        for (Object id : objects
        ) {
            CouponUseBo couponUseBo = isCanUse(userId, Integer.parseInt(id.toString()), carts);
            if (couponUseBo.isCanUse()) {
                count++;
            }
        }
        return count;
    }

    @Override
    public List<CouponVo> userCouponList(Integer userId, Integer type, Page<XwUserCoupon> page) {
        QueryWrapper<XwUserCoupon> wrapper = new QueryWrapper<XwUserCoupon>().eq("user_id", userId);
        if (type == 0) {
            wrapper.eq("`status`", 0)
                    .ge("coupon_expire_time", LocalDateTime.now());
        }

        if (type == 1) {
            wrapper.eq("`status`", 1);
        }

        if (type == 2) {
            wrapper.eq("`status`", 0)
                    .lt("coupon_expire_time", LocalDateTime.now());
        }
        page(page, wrapper);
        List<CouponVo> couponVos = Lists.newArrayListWithCapacity(page.getRecords().size());
        page.getRecords().forEach(s -> {
            CouponVo couponVo = buildCouponVo(s);
            couponVos.add(couponVo);
        });
        return couponVos;
    }


    @Override
    public Map<String, Object> choiceList(Integer userId, List<XwCart> carts) {
        List<XwUserCoupon> userCoupons = list(new QueryWrapper<XwUserCoupon>()
                .eq("user_id", userId)
                .eq("`status`", 0)
                .ge("coupon_expire_time", LocalDateTime.now()));

        Map<String, Object> result = Maps.newHashMap();
        List<CouponVo> couponVos = Lists.newArrayListWithCapacity(userCoupons.size());
        List<CouponVo> unCouponVos = Lists.newArrayListWithCapacity(userCoupons.size());
        for (XwUserCoupon userCoupon : userCoupons
        ) {
            CouponUseBo couponUseBo = isCanUse(userId, userCoupon.getId(), carts);
            if (couponUseBo.isCanUse()) {
                CouponVo couponVo = buildCouponVo(userCoupon);
                couponVos.add(couponVo);
            } else {
                CouponVo couponVo = buildCouponVo(userCoupon);
                couponVo.setErrMsg(couponUseBo.getReason());
                unCouponVos.add(couponVo);
            }
        }
        result.put("able", couponVos);
        result.put("unable", unCouponVos);
        return result;
    }

    private CouponVo buildCouponVo(XwUserCoupon userCoupon) {
        CouponVo couponVo = new CouponVo();
        couponVo.setId(userCoupon.getId());
        couponVo.setAmount(userCoupon.getCouponAmount());
        couponVo.setTitle(userCoupon.getCouponTitle());
        if (userCoupon.getCouponType().equals(CouponType.NO_CONDITION.getCode())) {
            couponVo.setAmountCondition(CouponConstant.NO_LIMIT_AMOUNT);
        }

        if (userCoupon.getCouponType().equals(CouponType.TO_AMOUNT.getCode())) {
            couponVo.setAmountCondition(String.format(CouponConstant.LIMIT_AMOUNT, userCoupon.getCouponConditionAmount().intValue()));
        }
        couponVo.setProductCondition(userCoupon.getCouponExplain());
        couponVo.setExpireTime(String.format(CouponConstant.EXPIRE_TIME,
                userCoupon.getCouponExpireTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))));
        return couponVo;
    }

}
